<?php
/**
 * 列表服务
 * User: dxk
 * Date: 2020/07/18
 */

namespace App\Component\ListService;
abstract class ListAbstract
{
    //主键字段名
    protected string $primary_key = 'id';
    //字段
    protected array $fields = [];
    protected array $ext_fields = [];
    //允许的字段
    protected array $allow_fields = [];
    protected bool $count_fields = false;//如果是复合sql 请传
    protected bool $count_field_use_select = false;//如果 获取总数sql 使用 select 的
    //允许获取的扩展字段
    protected array $allow_ext_fields = [];
    //默认返回的字段
    protected array $default_fields = [];
    //页码
    protected int $page = 1;
    protected int $page_size = 20;
    protected array $allow_sort = [];//允许排序字段
    protected array $default_sort_by = [];
    protected array $sort_by = [];
    //参数
    protected array $params = [];

    /**
     * 设置参数
     * @param string $key
     * @param $value
     * @param bool $auto_trim
     */
    protected function setParam(string $key, $value, $auto_trim = true)
    {
        if ($auto_trim) {
            if (is_string($value) || is_null($value)) $value = trim($value);
           /* if (is_int($value)) {
                $value = (int)$value;
            } elseif (is_numeric($value)) {
                $value = (float)$value;
            }*/
        }
        $this->params[$key] = $value;
    }

    /**
     * 获取参数
     * @param string $key
     * @param mixed $default
     * @return mixed
     */
    protected function getParam(string $key, $default = '')
    {
        if (array_key_exists($key, $this->params)) {
            return $this->params[$key];
        } else {
            return $default;
        }
    }

    /**
     * 获取字段
     * @param array $fields
     * @return $this
     */
    public function setFields(array $fields)
    {
        $this->fields = $fields;
        return $this;
    }

    /**
     * 设置分页
     * @param int $page
     * @param int $page_size
     * @return $this
     */
    public function setPage($page = 1, $page_size = 20)
    {
        $this->page = (int)$page;
        $this->page_size = (int)$page_size;
        return $this;
    }

    /**
     * 排序
     * @param string $sort 字段名
     * @param string $order 排序
     * @return $this
     */
    public function setSort($sort, $order = 'desc')
    {
        $sort = trim(strtolower($sort));
        $order = trim(strtolower($order));
        if (in_array($sort, $this->allow_sort)) {
            $this->sort_by[$sort] = $order;
        }
        return $this;
    }

    /**
     * 列表
     * @param bool $use_has_next 是否不获取总数，采用是否有下一页的模式
     * @return array
     */
    public function getList($use_has_next = false)
    {
        $use_has_next = (boolean)$use_has_next;
        //页码
        $page = (int)$this->page;
        $page = $page < 1 ? 1 : $page;
        $page_size = (int)$this->page_size;
        $page_size = $page_size < 1 ? 20 : $page_size;
        $page_size = $page_size > 2000 ? 2000 : $page_size;
        $offset = $page_size * ($page - 1);
        //有效字段
        if (empty($this->fields)) {
            $this->fields = $this->default_fields;
        }
        if (!empty($this->allow_fields)) {
            $this->fields = easy_get_valid_field($this->fields, array_merge($this->allow_fields, $this->allow_ext_fields));
            if (empty($this->fields)) {
                $this->fields = $this->default_fields;
            }
        }
        //扩展字段
        $this->ext_fields = easy_get_valid_field($this->fields, $this->allow_ext_fields);
        if (empty($this->ext_fields)) {
            if (!empty($this->allow_fields)) {
                $query_fields = easy_get_valid_field($this->fields, $this->allow_fields);
            } else {
                $query_fields = $this->fields;
            }
            if (empty($query_fields)) {
                $query_fields = $this->allow_fields ?: ['*'];
            }
        } else {
            $query_fields = $this->allow_fields ?: ['*'];
        }
        //获取数据
        $result = ['page' => $page, 'page_size' => $page_size, 'list' => []];
        if ($use_has_next) {
            $result['has_next'] = 0;
        } else {
            $result['total'] = 0;
        }
        $query_obj = $this->getQueryObj();
        if (is_bool($query_obj)) {
            return $result;
        }
        //获取总数
        $limit = $page_size;
        if ($use_has_next === false) {
            if (!$this->count_fields) {
                $result['total'] = $query_obj->getCountForPagination();
            } else if ($this->count_field_use_select) {
                $count_query = clone $query_obj;
                $sql = "select count(1) as num from (" . $count_query->toSql() . ") as tmp_table";
                $get_count = $query_obj->getConnection()->selectOne($sql, $query_obj->getBindings());
                $result['total'] = $get_count['num'];
            } else {
                $count_query = clone $query_obj;
                $sql = "select count(1) as num from (" . $count_query->select($this->primary_key)->toSql() . ") as tmp_table";
                $get_count = $query_obj->getConnection()->selectOne($sql, $query_obj->getBindings());
                $result['total'] = $get_count['num'];
            }
        } else {
            $limit = $page_size + 1;
        }
        if (method_exists($this, 'minPrimaryQuery') && property_exists($this, 'min_primary_id') && is_numeric($this->min_primary_id)) {
            $query_obj = call_user_func([$this, 'minPrimaryQuery'], $query_obj);
            $query_fields[] = $this->primary_key . ' as min_primary_id';
        } else {
            if ($this->sort_by) {
                foreach ($this->sort_by as $column => $order) {
                    $query_obj->orderBy($column, $order);
                }
            } elseif ($this->default_sort_by) {
                foreach ($this->default_sort_by as $column => $order) {
                    $query_obj->orderBy($column, $order);
                }
            }
        }
        //获取数据列表
        $list = $query_obj->limit($limit)->offset($offset)->addSelect($query_fields)->get()->toArray();
        //easy_p($query_obj->toSql(), $query_obj->getBindings());
        if ($use_has_next !== false) {
            if (count($list) > $page_size) {
                unset($list[$page_size]);
                $result['has_next'] = 1;
            } else {
                $result['has_next'] = 0;
            }
        }
        if (method_exists($this, 'minPrimaryQuery') && property_exists($this, 'min_primary_id') && is_numeric($this->min_primary_id)) {
            if (empty($list)) {
                $result['last_min_primary_id'] = $this->min_primary_id;
            } else {
                $result['last_min_primary_id'] = last($list)['min_primary_id'];
            }
        }
        //获取扩展字段数据
        $show_fields = [];
        foreach ($this->fields as $v) {
            $v = explode('.', $v);
            $show_fields[] = end($v);
        }
        if (method_exists($this, 'getExtField') && !empty($this->ext_fields)) {
            foreach ($list as $k => $item) {
                $item = call_user_func([$this, 'getExtField'], $item);
                //剔除不获取的字段
                if (!in_array('*', $show_fields)) {
                    foreach ($item as $fields_k => $fields_v) {
                        if (!in_array($fields_k, $show_fields)) {
                            unset($item[$fields_k]);
                        }
                    }
                }
                $list[$k] = $item;
            }
        }
        $result['list'] = easy_clean_xss($list);
        return $result;
    }

    /**
     * 获取总数
     * @return int
     */
    public function getTotalNum()
    {
        $query_obj = $this->getQueryObj();
        if (is_bool($query_obj)) {
            return 0;
        }
        if (!$this->count_fields) {
            $total = $query_obj->getCountForPagination();
        } else if ($this->count_field_use_select) {
            $count_query = clone $query_obj;
            $sql = "select count(1) as num from (" . $count_query->toSql() . ") as tmp_table";
            $get_count = $query_obj->getConnection()->selectOne($sql, $query_obj->getBindings());
            $total = $get_count['num'];
        } else {
            $count_query = clone $query_obj;
            $sql = "select count(1) as num from (" . $count_query->select($this->primary_key)->toSql() . ") as tmp_table";
            $get_count = $query_obj->getConnection()->selectOne($sql, $query_obj->getBindings());
            $total = $get_count['num'];
        }
        return $total;
    }

    /**
     * 获取主键
     * @return string
     */
    public function getPrimaryKey()
    {
        return $this->primary_key;
    }

    /**
     * 获取查询对象 返回bool类型表示未查到
     * @return bool|\Illuminate\Database\Query\Builder
     */
    abstract protected function getQueryObj();

    /**
     * 获取扩展字段
     * @param array $row
     * @return array
     */
    protected function getExtField(array $row)
    {
        return $row;
    }

    /**
     * @param $method
     * @param $parameters
     * @return $this
     */
    public function __call($method, $parameters)
    {
        if (count($parameters) != 1) {
            throw new \Exception('不支持的方法');
        }
        $method = \Str::kebab($method);
        $method = explode('-', $method);
        unset($method[0]);
        $method = implode('_', $method);
        if (!empty($method)) {
            $this->setParam($method, $parameters[0]);
        }
        return $this;
    }
}
